//*****************************************************************// 
//																   //
//			Thanx to Jeff Molofee for all the cool OpenGL		   //
//		  tutorials and the base code used in this project		   //
//																   //
//	    also Thanx to Patrick Quinn for the Bass BargraphDemo	   //
//	  even though the source was in delhi (which i don't know)	   //
//		 it was commented well enough to give me a starting		   //
//			      point for decoding the FFT Data.				   //
//																   //
//					 Author: Michael Hullinger				       //
//				Date: March 20 first 2000 and three				   //
//																   //
//*****************************************************************// 

#ifndef __SPECTRUM_H__
#define __SPECTRUM_H__

#pragma comment(lib, "Bass.lib")          // force compiler to search for Bass.lib at compile time
#include "bass.h"						  // header file for the bass library

HSTREAM music;							  // handle for current song

#define START_POSITION   0                // start position of song
#define BAND_HEIGHT		15				  // vertical height - number of LED's		

float ColorShift[BAND_HEIGHT];			  // used to interpolate color

// got this from Patrick Quinn (why change a good thing)
// used to log scale the vertical height - helps make  
// high frequencies more visible
const int LOG_LOOKUP[256] = { 
	  0,   0,  32,  51,  64,  74,  82,  90,
	 96, 101, 106, 110, 114, 118, 121, 125,
	128, 130, 133, 135, 138, 140, 142, 144,
	146, 148, 150, 152, 153, 155, 157, 158,
	159, 161, 162, 164, 165, 166, 167, 169,
	170, 171, 172, 173, 174, 175, 176, 177,
	178, 179, 180, 181, 182, 183, 184, 184,
	185, 186, 187, 188, 188, 189, 190, 191,
	191, 192, 193, 193, 194, 195, 196, 196,
	197, 197, 198, 199, 199, 200, 200, 201,
	202, 202, 203, 203, 204, 204, 205, 206,
	206, 207, 207, 208, 208, 209, 209, 210,
	210, 211, 211, 211, 212, 212, 213, 213,
	214, 214, 215, 215, 215, 216, 216, 217,
	217, 218, 218, 218, 219, 219, 220, 220,
	220, 221, 221, 221, 222, 222, 223, 223,
	223, 224, 224, 224, 225, 225, 225, 226,
	226, 226, 227, 227, 227, 228, 228, 228,
	229, 229, 229, 230, 230, 230, 231, 231,
	231, 231, 232, 232, 232, 233, 233, 233,
	234, 234, 234, 234, 235, 235, 235, 236,
	236, 236, 236, 237, 237, 237, 237, 238,
	238, 238, 238, 239, 239, 239, 239, 240,
	240, 240, 240, 241, 241, 241, 241, 242,
	242, 242, 242, 243, 243, 243, 243, 244,
	244, 244, 244, 245, 245, 245, 245, 245,
	246, 246, 246, 246, 247, 247, 247, 247,
	247, 248, 248, 248, 248, 248, 249, 249,
	249, 249, 249, 250, 250, 250, 250, 250,
	251, 251, 251, 251, 251, 252, 252, 252,
	252, 252, 253, 253, 253, 253, 253, 254,
	254, 254, 254, 254, 254, 255, 255, 255};

void GenerateColorShift()  // fill the colorShift array
{
	float steps = 1 / float (BAND_HEIGHT - 1);

	for(int i = 0; i < BAND_HEIGHT - 1; i++)
	{
		ColorShift[i] = i * steps; 
	}
	// this keeps the last index from going over 1.0
	ColorShift[BAND_HEIGHT - 1] = 1.0f;
}

void DrawTime()
{
	glLoadIdentity();
	glColor3f(1.0f, 1.0f, 1.0f);
	// get current position and convert to seconds
	QWORD channelPosition = BASS_ChannelGetPosition(music);
	float currentTime = BASS_ChannelBytes2Seconds(music, channelPosition);

	// get song length and convert to seconds
	QWORD length = BASS_StreamGetLength(music);
	float songLength = BASS_ChannelBytes2Seconds(music, length);
 
	// calculate current position of slider
	// percent fininshed * bar length - slider width
	float position = currentTime / songLength *  (600 - 6);

	glLoadIdentity();
	glLineWidth(2.0f);
	glColor3f(0.0f,0.0f,1.0f);
	
	// Draw position bar
	glBegin(GL_LINES);									   
		glVertex2d(100.0f, 340.0f);							 
		glVertex2d(700.0f, 340.0f);							 								 
	glEnd();

	// Draw position bar outter border
	glLineWidth(1.0f);
	glColor3f(0.5f, 0.5f, 1.0f);
	glBegin(GL_LINE_STRIP);
		glVertex2d(90.0f,  330.0f);							 
		glVertex2d(710.0f, 330.0f);	
		glVertex2d(710.0f, 351.0f);
		glVertex2d(90.0f,  351.0f); 
		glVertex2d(90.0f,  330.0f);
	glEnd();

	// Draw position bar inner border
	glColor3f(0.1f, 0.1f, 1.0f);
	glBegin(GL_LINE_STRIP);
		glVertex2d(91.0f,  331.0f);							 
		glVertex2d(709.0f, 331.0f);	
		glVertex2d(709.0f, 350.0f);
		glVertex2d(91.0f,  350.0f); 
		glVertex2d(91.0f,  331.0f);
	glEnd();

	// translate to slider position
	// bar start + 1/2 width of slider + current position
	glTranslatef(103.0f + position, 340.0f, 0.0f);
	
	// Draw position slider
	glColor3f(0.5f,0.5f,1.0f);
	glBegin(GL_QUADS);
		glVertex3f(-3.0f,  6.0f, 0.0f);
		glVertex3f( 3.0f,  6.0f, 0.0f);
		glVertex3f( 3.0f, -6.0f, 0.0f);
		glVertex3f(-3.0f, -6.0f, 0.0f);
	glEnd();
}

void DrawMusicLevel()
{
	DWORD level = BASS_ChannelGetLevel(music);
	// level contains 2 values from 0 - 128  
	// to indicate left/right levels
	int left  = BAND_HEIGHT * LOWORD(level) / 128;
	int right = BAND_HEIGHT * HIWORD(level) / 128;

	glLoadIdentity();
	glTranslatef(410.0f, 300.0f, 0.0f);

	for(int l = 0; l < BAND_HEIGHT; l++)			// loop through all LED's
	{
		if (l < left)								// if current LED is less than left level
		{	
			glColor3f(1.0f, ColorShift[l], 0.0f);	// use LED's corresponding color
			glBegin(GL_QUADS);
				glVertex3f(-7.0f,  3.0f, 0.0f);		// draw the LED
				glVertex3f( 7.0f,  3.0f, 0.0f);
				glVertex3f( 7.0f, -3.0f, 0.0f);
				glVertex3f(-7.0f, -3.0f, 0.0f);
			glEnd();
		}                                                        
		glTranslatef(0.0f, -10.0f, 0.0f);           // translate up to draw next LED
	}

	glTranslatef(-20.0f, BAND_HEIGHT * 10.0f, 0.0f);// translate back down and over to start right band

	for(int r = 0; r < BAND_HEIGHT; r++)			// loop through all LED's
	{
		if (r < right)								// if current LED is less than right level
		{
			glColor3f(1.0f, ColorShift[r], 0.0f);	// use LED's corresponding color
			glBegin(GL_QUADS);
				glVertex3f(-7.0f,  3.0f, 0.0f);		// draw the LED
				glVertex3f( 7.0f,  3.0f, 0.0f);
				glVertex3f( 7.0f, -3.0f, 0.0f);
				glVertex3f(-7.0f, -3.0f, 0.0f);
			glEnd();
		}
		glTranslatef(0.0f, -10.0f, 0.0f);			// translate up to draw next LED
	} 

	static int leftCap = 0;							// current height of left cap
	static int rightCap = 0;						// current height of right cap
	leftCap -= 1;									// decrease height of left cap a little
	rightCap -= 1;									// decrease height of right cap a little
	// if leftCap is lower than current left - move it up top
	if (leftCap < (left * 10)) leftCap = (left * 10);     
	// if rightCap is lower than current right - move it up top
	if (rightCap < (right * 10)) rightCap = (right * 10);

	glLoadIdentity();
	glTranslatef(410.0f, 300.0f - leftCap, 0.0f);
	glColor3f(0.9f,0.9f,0.9f);
	
	if (leftCap > 0)								// if cap is greater than 0
	{
		glBegin(GL_QUADS);							// draw leftCap
			glVertex3f(-7.0f,  3.0f, 0.0f);
			glVertex3f( 7.0f,  3.0f, 0.0f);
			glVertex3f( 7.0f, -3.0f, 0.0f);
			glVertex3f(-7.0f, -3.0f, 0.0f);
		glEnd();	
	}
	// translate over and adjust for rightCap height
	glTranslatef(-20.0f, float(leftCap - rightCap), 0.0f);
	if (rightCap > 0)								// if cap is greater than 0
	{
		glBegin(GL_QUADS);
			glVertex3f(-7.0f,  3.0f, 0.0f);			// draw rightCap 
			glVertex3f( 7.0f,  3.0f, 0.0f);
			glVertex3f( 7.0f, -3.0f, 0.0f);
			glVertex3f(-7.0f, -3.0f, 0.0f);
		glEnd();
	}
}

void DrawMusicSpectrum()
{ 
	float FFTData[1024];                  // array to hold FFT Data

	int SpectrumLeftBand[18];             // array for left bands - horizontal scale is in half octaves
	int SpectrumRightBand[18];			  // array for right bands - horizontal scale is in half octaves
	int SpectrumLeftValue = 0;			  // storage for current left sample data
	int SpectrumRightValue = 0;			  // storage for current right sample data

	// initalize all to 0
	for (int i = 0; i < 18; i++)
	{
		SpectrumLeftBand[i] = 0;
		SpectrumRightBand[i] = 0;
	}
    // attemp to get FFT data ... -1 = error
	if(BASS_ChannelGetData(music, FFTData, BASS_DATA_FFT1024S) != -1)
	{
		for (i = 0; i < 512; i++)  // loop through data
		{
			// calculate each spectrum value and log scale it
			// in a stero sample left and right values are 
			// alternated through the sample 
			SpectrumLeftValue  = BAND_HEIGHT * LOG_LOOKUP[int(FFTData[i * 2] * 255)] / 255;
			SpectrumRightValue = BAND_HEIGHT * LOG_LOOKUP[int(FFTData[i * 2 + 1] * 255)] / 255;

			// for linear scaling of data  -  
//			SpectrumLeftValue = FFTData[i * 2] * BAND_HEIGHT * 10;
//			SpectrumRightValue = FFTData[i * 2 + 1] * BAND_HEIGHT * 10;

			// calculate the frequency that i represents
			// 44100 is sample rate playing and 1024 is our sample size of it
			int f = i * 44100 / 1024; 
			if ((f >= 1) && (f <= 65))						// if frequency is greater than 
			{												// 1 Hz and less than 65 Hz
				SpectrumLeftBand[0]  +=  SpectrumLeftValue; // add to left band total
				SpectrumRightBand[0] += SpectrumRightValue; // add to right band total
			}
			else if ((f >= 66) && (f <= 86))				// and on and on etc ... 
			{	
				SpectrumLeftBand[1]  +=  SpectrumLeftValue; 
				SpectrumRightBand[1] += SpectrumRightValue;
			}
			else if ((f >= 87) && (f <= 129)) 
			{	
				SpectrumLeftBand[2]  +=  SpectrumLeftValue; 
				SpectrumRightBand[2] += SpectrumRightValue;
			}
			else if ((f >= 130) && (f <= 172)) 
			{	
				SpectrumLeftBand[3]  +=  SpectrumLeftValue; 
				SpectrumRightBand[3] += SpectrumRightValue;
			}
			else if ((f >= 173) && (f <= 258)) 
			{	
				SpectrumLeftBand[4]  +=  SpectrumLeftValue;
				SpectrumRightBand[4] += SpectrumRightValue;
			}
			else if ((f >= 259) && (f <= 345)) 
			{	
				SpectrumLeftBand[5]  +=  SpectrumLeftValue;
				SpectrumRightBand[5] += SpectrumRightValue;
			}
			else if ((f >= 345) && (f <= 517)) 
			{	
				SpectrumLeftBand[6]  +=  SpectrumLeftValue;
				SpectrumRightBand[6] += SpectrumRightValue;
			}
			else if ((f >= 518) && (f <= 689)) 
			{	
				SpectrumLeftBand[7]  +=  SpectrumLeftValue;
				SpectrumRightBand[7] += SpectrumRightValue;
			}
			else if ((f >= 690) && (f <= 1034)) 
			{	
				SpectrumLeftBand[8]  +=  SpectrumLeftValue; 
				SpectrumRightBand[8] += SpectrumRightValue;
			}
			else if ((f >= 1035) && (f <= 1378)) 
			{	
				SpectrumLeftBand[9]  +=  SpectrumLeftValue;
				SpectrumRightBand[9] += SpectrumRightValue;
			}
			else if ((f >= 1379) && (f <= 2067)) 
			{	
				SpectrumLeftBand[10]  +=  SpectrumLeftValue;
				SpectrumRightBand[10] += SpectrumRightValue;
			}
			else if ((f >= 2068) && (f <= 2756)) 
			{	
				SpectrumLeftBand[11]  +=  SpectrumLeftValue;
				SpectrumRightBand[11] += SpectrumRightValue;
			}
			else if ((f >= 2757) && (f <= 4134)) 
			{	
				SpectrumLeftBand[12]  +=  SpectrumLeftValue;
				SpectrumRightBand[12] += SpectrumRightValue;
			}
			else if ((f >= 4135) && (f <= 5512)) 
			{	
				SpectrumLeftBand[13]  +=  SpectrumLeftValue;
				SpectrumRightBand[13] += SpectrumRightValue;
			}
			else if ((f >= 5513) && (f <= 8268)) 
			{	
				SpectrumLeftBand[14]  +=  SpectrumLeftValue;
				SpectrumRightBand[14] += SpectrumRightValue;
			}
			else if ((f >= 8269) && (f <= 11025)) 
			{	
				SpectrumLeftBand[15]  +=  SpectrumLeftValue;
				SpectrumRightBand[15] += SpectrumRightValue;
			}
			else if ((f >= 11026) && (f <= 16537)) 
			{	
				SpectrumLeftBand[16]  +=  SpectrumLeftValue;
				SpectrumRightBand[16] += SpectrumRightValue;
			}
			else if ((f >= 16538) && (f <= 22050)) 
			{	
				SpectrumLeftBand[17]  +=  SpectrumLeftValue;
				SpectrumRightBand[17] += SpectrumRightValue;
			}
		}
		// divide each band by the number of frequencies that 
		// were added to it to get an average value for each band
		SpectrumLeftBand[4]  =    SpectrumLeftBand[4] / 2;
		SpectrumLeftBand[5]  =    SpectrumLeftBand[5] / 2;
		SpectrumLeftBand[6]  =    SpectrumLeftBand[6] / 4;
		SpectrumLeftBand[7]  =    SpectrumLeftBand[7] / 4;
		SpectrumLeftBand[8]  =    SpectrumLeftBand[8] / 8;
		SpectrumLeftBand[9]  =    SpectrumLeftBand[9] / 8;
		SpectrumLeftBand[10] =  SpectrumLeftBand[10] / 16;
		SpectrumLeftBand[11] =  SpectrumLeftBand[11] / 16;
		SpectrumLeftBand[12] =  SpectrumLeftBand[12] / 32;
		SpectrumLeftBand[13] =  SpectrumLeftBand[13] / 32;
		SpectrumLeftBand[14] =  SpectrumLeftBand[14] / 64;
		SpectrumLeftBand[15] =  SpectrumLeftBand[15] / 64;
		SpectrumLeftBand[16] = SpectrumLeftBand[16] / 128;
		SpectrumLeftBand[17] = SpectrumLeftBand[17] / 128;
		// divide each band by the number of frequencies that 
		// were added to it to get an average value for each band
		SpectrumRightBand[4]  =    SpectrumRightBand[4] / 2;
		SpectrumRightBand[5]  =    SpectrumRightBand[5] / 2;
		SpectrumRightBand[6]  =    SpectrumRightBand[6] / 4;
		SpectrumRightBand[7]  =    SpectrumRightBand[7] / 4;
		SpectrumRightBand[8]  =    SpectrumRightBand[8] / 8;
		SpectrumRightBand[9]  =    SpectrumRightBand[9] / 8;
		SpectrumRightBand[10] =  SpectrumRightBand[10] / 16;
		SpectrumRightBand[11] =  SpectrumRightBand[11] / 16;
		SpectrumRightBand[12] =  SpectrumRightBand[12] / 32;
		SpectrumRightBand[13] =  SpectrumRightBand[13] / 32;
		SpectrumRightBand[14] =  SpectrumRightBand[14] / 64;
		SpectrumRightBand[15] =  SpectrumRightBand[15] / 64;
		SpectrumRightBand[16] = SpectrumRightBand[16] / 128;
		SpectrumRightBand[17] = SpectrumRightBand[17] / 128;
	}

	glLoadIdentity();
	glTranslatef(440.0f, 300.0f, 0.0f);						// translate to start position of right bands
	for(int a = 0; a < 18; a++)								// loop through all left bands
	{
		for(int c = 0; c < BAND_HEIGHT; c++)				// loop through all left LED's
		{													
			if (c < SpectrumLeftBand[a])					// if current LED is less than left level
			{
				glColor3f(1.0f,1.0f - ColorShift[c],0.0f);	// use LED's corresponding color
				glBegin(GL_QUADS);
					glVertex3f(-7.0f,  3.0f, 0.0f);			// Draw the LED
					glVertex3f( 7.0f,  3.0f, 0.0f);
					glVertex3f( 7.0f, -3.0f, 0.0f);
					glVertex3f(-7.0f, -3.0f, 0.0f);
				glEnd();
			}
			glTranslatef(0.0f, -10.0, 0.0f);				// translate up to draw the next LED
		}
		glTranslatef(20.0f, BAND_HEIGHT * 10.0f, 0.0f);     // translate back down and over to draw next band
	}

    glLoadIdentity();
	glTranslatef(360.0f, 300.0f, 0.0f);						// translate to start position of right bands
	for(a = 0; a < 18; a++)									// loop through all right bands
	{
		for(int c = 0; c < BAND_HEIGHT; c++)				// loop through all right LED's
		{
			if (c < SpectrumRightBand[a])					// if current LED is less than right level
			{
				glColor3f(1.0f,1.0f - ColorShift[c],0.0f);	// use LED's corresponding color
				glBegin(GL_QUADS);
					glVertex3f(-7.0f,  3.0f, 0.0f);			// Draw the LED
					glVertex3f( 7.0f,  3.0f, 0.0f);
					glVertex3f( 7.0f, -3.0f, 0.0f);
					glVertex3f(-7.0f, -3.0f, 0.0f);
				glEnd();	 
			}
			glTranslatef(0.0f, -10.0f, 0.0f);				// translate up to draw the next LED
		}
		glTranslatef(-20.0f, BAND_HEIGHT * 10.0f, 0.0f);	// translate back down and over to draw next band
	}	

	static int leftCap[18]  = {0};							// current height of left caps
	static int rightCap[18] = {0};							// current height of right caps

	for (i = 0; i < 18; i++)
	{
		leftCap[i]  -= 1;									// decrease height of left caps a little
		rightCap[i] -= 1;									// decrease height of right caps a little
		// if leftCap is lower than current left - move it up to top
		if (leftCap[i] < (SpectrumLeftBand[i] * 10)) leftCap[i] = (SpectrumLeftBand[i] * 10);
		// if rightCap is lower than current right - move it up to top
		if (rightCap[i] < (SpectrumRightBand[i] * 10)) rightCap[i] = (SpectrumRightBand[i] * 10);
	}

	glColor3f(0.9f, 0.9f, 0.9f);
	glLoadIdentity();
	glTranslatef(440.0f, 300.0f, 0.0f);					// translate to start position of left bands

	for(i = 0; i < 18; i++)								// loop through all left bands
	{
		glTranslatef(0.0f, float(-leftCap[i]), 0.0f);   // translate to cap height
		if (leftCap[i] > 0)							    // if cap is greater than 0
		{
			glBegin(GL_QUADS);
				glVertex3f(-7.0f,  3.0f, 0.0f);			// draw the LED
				glVertex3f( 7.0f,  3.0f, 0.0f);
				glVertex3f( 7.0f, -3.0f, 0.0f);
				glVertex3f(-7.0f, -3.0f, 0.0f);
			glEnd();
		}
		glTranslatef(20.0f, float(leftCap[i]), 0.0f);  // translate back down and over to draw next cap
	}
	
	glLoadIdentity();
	glTranslatef(360.0f, 300.0f, 0.0f);					// translate to start position of right bands

	for(i = 0; i < 18; i++)								// loop through all right bands
	{
		glTranslatef(0.0f, float(-rightCap[i]), 0.0f);  // translate to cap height
		if (rightCap[i] > 0)							// if cap is greater than 0
		{
			glBegin(GL_QUADS);
				glVertex3f(-7.0f,  3.0f, 0.0f);			// draw the LED
				glVertex3f( 7.0f,  3.0f, 0.0f);
				glVertex3f( 7.0f, -3.0f, 0.0f);
				glVertex3f(-7.0f, -3.0f, 0.0f);
			glEnd();
		}
		glTranslatef(-20.0f, float(rightCap[i]), 0.0f);// translate back down and over to draw next cap
	}
}

#endif  // __SPECTRUM_H__
